001 /*
002 * Copyright (c) 2005 Stephen J. McConnell
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.metro.tools;
020
021 import java.io.IOException;
022 import java.util.LinkedList;
023 import java.util.List;
024 import java.beans.IntrospectionException;
025
026 import net.dpml.metro.info.Type;
027 import net.dpml.metro.info.PartReference;
028
029 import net.dpml.tools.tasks.GenericTask;
030
031 import org.apache.tools.ant.BuildException;
032 import org.apache.tools.ant.DynamicElementNS;
033 import org.apache.tools.ant.Location;
034 import org.apache.tools.ant.Project;
035 import org.apache.tools.ant.Task;
036
037 /**
038 * A datatype that enables custom part builders.
039 *
040 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
041 * @version 1.1.0
042 */
043 public class PartsDataType extends GenericTask implements DynamicElementNS
044 {
045 private List m_builders = new LinkedList();
046 private Task m_owner;
047
048 /**
049 * Creation of a new parts data type.
050 * @param owner the owning task
051 */
052 public PartsDataType( Task owner )
053 {
054 Project proj = owner.getProject();
055 setProject( proj );
056 m_owner = owner;
057 }
058
059 /**
060 * Create a new component builder task.
061 * @return a new component builder task
062 */
063 public ComponentBuilderTask createComponent()
064 {
065 ComponentBuilderTask builder = new ComponentBuilderTask();
066 m_builders.add( builder );
067 return builder;
068 }
069
070 /**
071 * Create a new part datatype.
072 * @return the nwew part datatype
073 */
074 public PartDataType createPart()
075 {
076 PartDataType builder = new PartDataType();
077 m_builders.add( builder );
078 return builder;
079 }
080
081 /**
082 * Create a new constructed value builder.
083 * @return a part builder
084 */
085 public EntryDataType createValue()
086 {
087 final EntryDataType builder = new EntryDataType();
088 m_builders.add( builder );
089 return builder;
090 }
091
092 /**
093 * Operation used to construct a custom part type directive.
094 * @param uri the part handler uri
095 * @param name the element name
096 * @param qualified the qualified name
097 * @return a dynamic part builder
098 */
099 public Object createDynamicElement( String uri, String name, String qualified )
100 {
101 String path = getProject().replaceProperties( uri );
102 PartReferenceBuilder builder = loadPartHandler( path, name );
103 if( null != builder )
104 {
105 m_builders.add( builder );
106 }
107 return builder;
108 }
109
110 private PartReferenceBuilder loadPartHandler( String uri, String name ) throws BuildException
111 {
112 String urn = uri + ":" + name;
113 Object builder = null;
114 PartReferenceBuilder partBuilder = null;
115 String target = m_owner.getOwningTarget().getName();
116 Location location = m_owner.getLocation();
117 ClassLoader context = Thread.currentThread().getContextClassLoader();
118 try
119 {
120 Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
121 Project proj = getProject();
122 builder = proj.createDataType( urn );
123 partBuilder = (PartReferenceBuilder) builder;
124 return partBuilder;
125 }
126 catch( ClassCastException e )
127 {
128 final String error =
129 "The custom part builder ["
130 + builder.getClass().getName()
131 + "] established by the uri ["
132 + urn
133 + "] declared by the element <"
134 + name
135 + "> under the task <"
136 + m_owner.getTaskName()
137 + "><parts> within the target <"
138 + target
139 + "> does not implement the net.dpml.metro.tools.PartReferenceBuilder interface.";
140 throw new BuildException( error, e );
141 }
142 catch( BuildException e )
143 {
144 final String error =
145 "Unable to load the plugin from the uri ["
146 + urn
147 + "] to handle the custom part type declared by the element <"
148 + name
149 + "> within <"
150 + m_owner.getTaskName()
151 + "><parts> under the target <"
152 + target
153 + ">.";
154 throw new BuildException( error, e );
155 }
156 catch( Throwable e )
157 {
158 final String error =
159 "Unexpected exception while attempting to load the custom part handler with the uri ["
160 + urn
161 + "] declared by the element <"
162 + name
163 + "> within <"
164 + m_owner.getTaskName()
165 + "><parts> under the target <"
166 + target
167 + ">.";
168 throw new BuildException( error, e );
169 }
170 finally
171 {
172 Thread.currentThread().setContextClassLoader( context );
173 }
174 }
175
176 /**
177 * Return the set of parts contained within this container.
178 * @return the contained parts
179 */
180 public PartReferenceBuilder[] getPartBuilders()
181 {
182 return (PartReferenceBuilder[]) m_builders.toArray( new PartReferenceBuilder[0] );
183 }
184
185 /**
186 * Return the set of parts contained within this parts collection.
187 * @param classloader the runtime classloader
188 * @param type the component type that references are relative to
189 * @return the contained parts
190 * @exception IntrospectionException if a class introspection error occurs
191 * @exception IOException if an I/O error occurs
192 * @exception ClassNotFoundException if a part class cannot be found
193 */
194 public PartReference[] getParts( ClassLoader classloader, Type type )
195 throws IntrospectionException, IOException, ClassNotFoundException
196 {
197 PartReferenceBuilder[] builders =
198 (PartReferenceBuilder[]) m_builders.toArray( new PartReferenceBuilder[0] );
199 PartReference[] parts = new PartReference[ builders.length ];
200 for( int i=0; i<builders.length; i++ )
201 {
202 PartReferenceBuilder builder = builders[i];
203 parts[i] = builder.buildPartReference( classloader, type );
204 }
205 return parts;
206 }
207 }